/*
 * $Id: AssetRegistrationHelper.java,v 1.9 2012/05/21 16:15:43 l501902876 Exp $
 * 
 * Copyright (C) 2010 General Electric Company. All Rights Reserved.
 * 
 * This software is the confidential and proprietary information of the General
 * Electric Company (GE). You shall not disclose this software and shall use it
 * only in accordance with the terms of the license agreement you entered into
 * with GE.
 * 
 * GE MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
 * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
 * NON-INFRINGEMENT. GE SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 * AS A RESULT OF USING, MODIFYING, OR DISTRIBUTING THIS SOFTWARE OR ITS
 * DERIVATIVES.
 */

package com.ge.healthcare.autosc.ui.assetReg.service;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import com.ge.healthcare.autosc.common.ASCLogger;
import com.ge.healthcare.autosc.common.ASCUtil;
import com.ge.healthcare.autosc.common.exceptions.PropertyException;
import com.ge.healthcare.autosc.common.util.ApplicationInfo;
import com.ge.healthcare.autosc.common.util.PropertyConstants;
import com.ge.healthcare.autosc.ui.assetReg.domain.SblAssetRegFailRec;
import com.ge.healthcare.autosc.ui.assetReg.exceptions.AssetRegisterException;
import com.ge.healthcare.gsccService.client.common.TransportMgr;
import com.ge.healthcare.gsccService.vo.DeleteRecordRequest;
import com.ge.healthcare.gsccService.vo.DeleteRecordResponse;
import com.ge.healthcare.gsccService.vo.GetAllRecordsRequest;
import com.ge.healthcare.gsccService.vo.GetAllRecordsResponse;
import com.ge.healthcare.gsccService.vo.InsertRecordRequest;
import com.ge.healthcare.gsccService.vo.InsertRecordResponse;
import com.ge.med.service.eds.commons.DataException;
import com.ge.med.service.eds.commons.ResourceException;
import com.ge.med.service.eds.system.Asset;
import com.ge.med.service.eds.system.SystemFactory;
import com.ge.med.service.eds.system.vo.AssetInformation;
import com.ge.med.service.eds.system.vo.RegisterRequest;
import com.ge.med.service.eds.system.vo.RegisterResponse;

public class AssetRegistrationHelper {

	private List<SblAssetRegFailRec> currentFailureRecords;
	boolean firstPageUpload = true;

	private String webServiceURI = null;

	public AssetRegistrationHelper() throws PropertyException {
		webServiceURI = ApplicationInfo.getInstance().getRequiredPropertyValue(
				PropertyConstants.GSCC_SERVICE_URL);
		// webServiceURI =
		// "http://localhost:7001/gsccService/services/assetReRegService";
	}

	public List<SblAssetRegFailRec> loadFailureRecords()
			throws AssetRegisterException {
		List<SblAssetRegFailRec> failureRecords = new ArrayList<SblAssetRegFailRec>();

		GetAllRecordsResponse _response = (GetAllRecordsResponse) this
				.getAllRecordsRequest( /* _path, new GetAllRecordsRequest() */);

		if (_response != null) {
			List<com.ge.healthcare.gsccService.client.model.SblAssetRegFailRec> _list = _response
					.getSblAssetRegFailRecList();

			if (null != _list) {
				for (com.ge.healthcare.gsccService.client.model.SblAssetRegFailRec sblAssRegFail : _list) {
					SblAssetRegFailRec sblAssetRegFailRec = convertModel2domain(sblAssRegFail);
					failureRecords.add(sblAssetRegFailRec);
				}
			}

		}

		firstPageUpload = false;
		return failureRecords;
	}

	private SblAssetRegFailRec convertModel2domain(
			com.ge.healthcare.gsccService.client.model.SblAssetRegFailRec sblAssetRegFailRec) {

		SblAssetRegFailRec sblAssetRegFailRecModel = new SblAssetRegFailRec();

		sblAssetRegFailRecModel.setConnType(sblAssetRegFailRec.getConnType());
		sblAssetRegFailRecModel.setFailureDate(sblAssetRegFailRec
				.getFailureDate());
		sblAssetRegFailRecModel.setFailureId(sblAssetRegFailRec.getFailureId());
		sblAssetRegFailRecModel.setRemoteAccessInfo(sblAssetRegFailRec
				.getRemoteAccessInfo());
		sblAssetRegFailRecModel.setSystemId(sblAssetRegFailRec.getSystemId());

		return sblAssetRegFailRecModel;
	}

	public List<SblAssetRegFailRec> getAllFailureRecord()
			throws AssetRegisterException {
		currentFailureRecords = loadFailureRecords();
		return currentFailureRecords;
	}

	public SblAssetRegFailRec getFailureRecord(String systemId)
			throws AssetRegisterException {

		List<SblAssetRegFailRec> failureRecords = getAllFailureRecord();

		if (failureRecords != null) {
			for (SblAssetRegFailRec failureRecord : failureRecords) {
				if (failureRecord.getSystemId().equals(systemId)) {
					return failureRecord;
				}
			}
		}
		return null;
	}

	public void registerAndRemoveRecord(SblAssetRegFailRec record,
			RegistrationType registrationType) throws AssetRegisterException,
			DataException, ResourceException {
		boolean response;
		switch (registrationType) {

		case IndividualRegistration:
			SblAssetRegFailRec sblAssetRegFailRec = this.getFailureRecord(record.getSystemId());
			response = this.addToSblAssetRec(sblAssetRegFailRec);
			if (response) {
				this.deleteFailureRecd(record.getSystemId());
			}
			break;
		case BatchRegistration:
			response = this.addToSblAssetRec(record);
			if (!response) {
				this.insertFailureRecd(record);
				//ASCLogger.error("No Asset found");
				//throw new AssetRegisterException("No Asset found");
			}
			break;
		case NewAssetRegistration:
			if(!this.addToSblAssetRec(record)){
				ASCLogger.error("No Asset found for " + record.getSystemId());
				throw new AssetRegisterException("No Asset found for " + record.getSystemId());
			}
			break;
		default:
			ASCLogger.error("Invalid registration operation");
			throw new AssetRegisterException("Invalid registration operation");
		}

	}

	private GetAllRecordsResponse getAllRecordsRequest( /*
														 * String fileName,
														 * Object req
														 */)
			throws AssetRegisterException {

		GetAllRecordsResponse _res = null;
		try {
			_res = TransportMgr.sendWsRequestToGsccService(
					new GetAllRecordsRequest(), webServiceURI);

			return _res;

		} catch (Exception e) {
			// Note at this point i don't care about validating response as this
			// is not an integration test, responses are validated separately by
			// GSCC Server
			ASCLogger.error("Caught Exception", e);
			throw new AssetRegisterException("Failed to load records", e);
		}

	}

	private InsertRecordResponse insertFailureRecd(SblAssetRegFailRec record) {
		InsertRecordRequest _req = new InsertRecordRequest();
		InsertRecordResponse _res = null;

		com.ge.healthcare.gsccService.client.model.SblAssetRegFailRec _sblAssetRegfail = new com.ge.healthcare.gsccService.client.model.SblAssetRegFailRec();
		_sblAssetRegfail.setSystemId(record.getSystemId());
		if ( record.getFailureDate() != null){
			_sblAssetRegfail.setFailureDate(record.getFailureDate());
		}else{
			_sblAssetRegfail.setFailureDate(new Date());
		}

		_sblAssetRegfail.setConnType(record.getConnType());

		_req.setSblAssetRegFailRec(_sblAssetRegfail);

		try {
			_res = TransportMgr.sendWsRequestToGsccService(_req, webServiceURI);

		} catch (Exception e) {
			ASCLogger.error(this.getClass(), "insertFailureRecd", "Caught Exception", e);
		}

		return _res;
	}

	public DeleteRecordResponse deleteFailureRecd(String systemId) {
		DeleteRecordRequest _req = new DeleteRecordRequest();
		DeleteRecordResponse _res = null;

		_req.setSystemId(systemId);

		try {
			_res = TransportMgr.sendWsRequestToGsccService(_req, webServiceURI);

		} catch (Exception e) {
			ASCLogger.error(this.getClass(), "deleteFailureRecd", "Caught Exception", e);
		}

		return _res;
	}

	private static final String CONTEXT_ID = "contextId";
	private static final String CONTEXT_NAME = "contextName";

	/**
	 * Gets the asset details
	 * 
	 * @param systemId
	 * @return
	 * @throws AppException
	 */
	private AssetInformation getAssetDetails(String systemId)
			throws AssetRegisterException {
		String methodName = "getAssetDetails";
		long startTime = System.currentTimeMillis();
		Asset assetReg = SystemFactory.getInstance().getAssetObject();
		try {
			AssetInformation assetInfo = assetReg.getDetails(systemId);
			ASCLogger.info(this.getClass(), methodName, String.format(
					"System:%s has asset details:%s", systemId, assetInfo));
			return assetInfo;
		} catch (Exception e) {
			ASCLogger.error(
					this.getClass(),
					"getAssetDetails",
					new StringBuffer().append(
							"Failed to retrieve asset details for System Id:")
							.append(systemId), e);
			throw new AssetRegisterException(new StringBuffer()
					.append("Failed to retrieve asset details for System Id:")
					.append(systemId).toString());
		} finally {
			long endTime = System.currentTimeMillis();
			ASCLogger.info(this.getClass(), methodName, String.format(
					"GetAssetDetails call took:%d ms", (endTime - startTime)));
		}
	}

	/**
	 * 
	 * Registers the asset in Siebel
	 * 
	 * @param connType
	 * @param remoteAccessInfo
	 * @param failureDate
	 * @param assetDetails
	 * @throws AppException
	 */
	public void performRegistration(String connType, String remoteAccessInfo,
			Date failureDate, AssetInformation assetDetails)
			throws AssetRegisterException {
		String methodName = "assetRegister";
		ASCLogger
				.info(this.getClass(),
						methodName,
						String.format(
								"Asset registration invoked with parameters:\nConnType:%s\nRemoteAccessInfo:%s\nFailureDate:%s\nAssetInfo:%s",
								connType, remoteAccessInfo, failureDate,
								assetDetails));
		try {
			RegisterRequest request = new RegisterRequest();
			request.setRemoteAccessMethod(connType);
			request.setAssetId(assetDetails.getAssetId());
			request.setCRM(assetDetails.getCrm());
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(failureDate);
			request.setRegistrationDate(calendar);
			if (ASCUtil.containsInProperty(
					PropertyConstants.CONNECTION_TYPES_FOR_REMOTE_ACCESS_INFO,
					",", connType)) {
				request.setSystemData(this.getSystemDataMap(remoteAccessInfo));
			}

			Asset assetReg = SystemFactory.getInstance().getAssetObject();
			RegisterResponse response = assetReg
					.setSiebelRegistrationDate(request);
			ASCLogger.info(
					this.getClass(),
					methodName,
					new StringBuffer().append("Received response:")
							.append(response).append(" for Request:")
							.append(request).toString());
		} catch (Exception e) {
			ASCLogger.error(this.getClass(), methodName,
					"Asset Registration Failed. Exception:" + e, e);
			throw new AssetRegisterException(e.getMessage(), e);
		}
	}

	/**
	 * Creates the system Data Map for Insite EXC systems
	 * 
	 * @param remoteAccessInfo
	 * @return
	 * @throws AppException
	 */
	private HashMap<String, String> getSystemDataMap(String remoteAccessInfo)
			throws AssetRegisterException {
		HashMap<String, String> systemDataMap = new HashMap<String, String>();
		if (ASCUtil.isNullOrEmpty(remoteAccessInfo)) {
			throw new AssetRegisterException(
					"System Data Map can't be null for Insite EXC Systems");
		}
		if (remoteAccessInfo.indexOf("<SEP>") == -1) {
			throw new AssetRegisterException(
					String.format(
							"Remote Access Info missing the seperator. RemoteAccessInfo: %s",
							remoteAccessInfo));
		}
		final String[] accessInfo = remoteAccessInfo.split("<SEP>");
		if (accessInfo == null || accessInfo.length != 2) {
			throw new AssetRegisterException(
					String.format(
							"Remote Access Info must have two parameters. RemoteAccessInfo: %s",
							remoteAccessInfo));
		}
		systemDataMap.put(CONTEXT_ID, accessInfo[0]);
		systemDataMap.put(CONTEXT_NAME, accessInfo[1]);
		return systemDataMap;
	}

	private boolean addToSblAssetRec(SblAssetRegFailRec sblAssetRegFailRec)
			throws AssetRegisterException, DataException, ResourceException {

		AssetInformation assetInfo = this.getAssetDetails(sblAssetRegFailRec
				.getSystemId());
		if (assetInfo == null) {
			return false;
		}
		if (isSiebelCRM(assetInfo.getCrm())) {
			this.performRegistration(sblAssetRegFailRec.getConnType(),
					sblAssetRegFailRec.getRemoteAccessInfo(),
					sblAssetRegFailRec.getFailureDate(), assetInfo);
		}
		return true;

	}

	/**
	 * Identifies CRM is Siebel or not
	 * 
	 * @param crmId
	 * @return
	 */
	public static boolean isSiebelCRM(String crmId) {

		if (ASCUtil.containsInProperty(PropertyConstants.SIEBEL_CRM_IDS, ",",
				crmId)) {
			return true;
		} else
			return false;

	}

	public static enum RegistrationType {
		NewAssetRegistration, BatchRegistration, IndividualRegistration;

	}
}
